package cn.ch.basic.service.impl;

import cn.ch.basic.constant.BaseConstant;
import cn.ch.basic.constant.WeChatConstant;
import cn.ch.basic.dto.RegisterDto;
import cn.ch.basic.exception.BusinessException;
import cn.ch.basic.service.IVerifyCodeService;
import cn.ch.basic.util.StrUtils;
import cn.ch.basic.util.VerifyCodeUtils;
import cn.ch.user.domain.Logininfo;
import cn.ch.user.mapper.LogininfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;//注入RedisTemplate才能保存到redis里面
    @Autowired
    private LogininfoMapper logininfoMapper;//注入mapper调用方法到数据库查找phone

    /**
     * 获取图形验证码，通过base64转化，最后以String的形式返回到前台
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        //1. 参数进行空校验，没有就抛异常
        //1.5 不需要去验证redis是否存在。
        if(!StringUtils.hasLength(key)){//判断key的长度，如果为空，抛异常
            throw new BusinessException("请求传入的key不能为空！！！");
        }
        //2.生成四位随机码 StrUtils
        String code = StrUtils.getComplexRandomString(4);
        //3.随机码保存到redis 以key作为存储redis的key，并设置过期时间为5分钟
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);//调用里面的set方法设置传入到redis
        //4.将4位随机码转化成图片
        //5.将图片使用base64编码成String类型
        String str = VerifyCodeUtils.VerifyCode(110, 40, code);
        //6.返回String即可
        return str;
    }
    /**
     * 发送注册相关的短信验证码
     * @param dto
     */
    private void sendRegister(RegisterDto dto) {
        // 2.后端接收参数 各种判断一波  校验手机号是否注册了
        if(StringUtils.isEmpty(dto.getPhone())
                || StringUtils.isEmpty(dto.getImageKey())
                || StringUtils.isEmpty(dto.getImageCode())
        ){
            throw new BusinessException("参数有问题！！");
        }
        String phone = dto.getPhone();
        Logininfo logininfo = logininfoMapper.loadByPhone(phone);
        if(logininfo != null){
            throw new BusinessException("用户已注册，请直接登录！！！如果忘记密码，请走找回密码流程");
        }
//        3.校验图形验证码  不要区分大小写
        Object imgCode = redisTemplate.opsForValue().get(dto.getImageKey());
//        。校验是否有效 key（UUID）拿到 codeTmp说明有效
//        。校验是否相等  imgCode=codeTmp
        if(imgCode == null){
            throw new BusinessException("图形验证码已经失效，青重新获取");
        }
        if(!imgCode.toString().equalsIgnoreCase(dto.getImageCode())){
            throw new BusinessException("请输入正确的图形验证码！！");
        }

        //发送短信验证码
        String messageKey = BaseConstant.RegisterConstant.BUSSINESS_REGISTER_PREFIX+phone;
        sendMsg(messageKey);

    }
    /**
     * 公共的发送短信验证码接口
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
        //1.获取传入的类型type
        String type = dto.getType();
        if("register".equals(type)){//如果是register就注册
            //
            sendRegister(dto);
        }else if("binder".equals(type)){
            sendBinder(dto);
        }
    }

    /**
     * 发送绑定（binder）相关的短信验证码
     * @param dto
     */
    private void sendBinder(RegisterDto dto) {
        //发送短信验证码
        String messageKey = WeChatConstant.LoginConstant.BUSSINESS_BINDER_PREFIX+dto.getPhone();
        sendMsg(messageKey);
    }

    /**
     * 发送注册（register）相关的短信验证码
     * @param messageKey
     */
    public void sendMsg(String messageKey){
        //4.只有图形验证码相等，才能往下发送短信验证码
        //5.校验短信码是否有效

        //5.1拼接短信验证码key (register:phone)
        String msgCodeKey = messageKey;
        //5.2根据验证码从redis获取凭借的value (code:时间戳)
        Object msgCode = redisTemplate.opsForValue().get(msgCodeKey);
        //5.3把code抽出来
        String code = "";//短信验证码

        //6.对下面进行判断
        if(msgCode != null){// code：时间戳
        //6.1如果拿到了 说明有效，还没过3分钟失效时间
            Long oldTime = Long.valueOf(msgCode.toString().split(":")[1]);//3649841265712
        //6.2 判断是否过了重发时间（1分钟）
            if(System.currentTimeMillis() - oldTime <= 1 * 60 *1000){
        //6.3如果超时 报错
                throw new BusinessException("请勿重复获取验证码！！！");
            }
        //6.4如果过了 使用原来的code，重新存储redis设置过期时间 发短信
            code = msgCode.toString().split(":")[0]; //使用历史的验证码
        }else{
        //6.5如果拿不到重新生成验证码，存储redis，给他发短信
            code = StrUtils.getComplexRandomString(4);//生成新的验证码
        }
        //6.6存储redis并发送短信
        String  codeTmp =  code + ":"+System.currentTimeMillis();
        redisTemplate.opsForValue().set(
                msgCodeKey,
                codeTmp,
                3,
                TimeUnit.MINUTES
        );
        //6.7 发送验证码
        // SmsUtils.sendSmsMsg(phone, "您好！！，您的验证码是："+code+"，请在三分钟内使用！！！！");
        System.out.println("您好！！，您的验证码是："+code+"，请在三分钟内使用！！！！");
    }
}